package com.glsc.ngateway.common.api.common.utils.encrypt;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * AES加密工具类
 * encrypt(String src, byte[] key)和decrypt(String src, byte[] key)是一对，也是现在用的
 * <p>
 * encrypt(String content, String password)和decrypt(byte[] content, String password)是一对；
 *
 * TODO：是从ldap迁移过来的，目前与AESEncrypt重复，后面做整合
 */
public class CryptoUtil {
    private static Logger logger = LoggerFactory.getLogger(CryptoUtil.class);

    private static String iv = "0123456789ABCDEF";//偏移量字符串必须是16位 当模式是CBC的时候必须设置偏移量:
    //iv = "0123456789ABCDEF" byteToHexString=30313233343536373839414243444546
    private static byte key[];

    static {
        try {//key必须是32位
//          String originalKey="GATEWAYOA@2021#AESPASSORD%000000";

            String originalKey = "GATEWAYOA@2021#AESPASSORD%000000";

            // String originalKey= "AMPRODUCT@2020#AESPASSORD%000000";

            key = originalKey.getBytes("utf-8");
            //414d50524f44554354403230323023414553504153534f524425303030303030
            System.out.println("originalKey=" + originalKey + ",getBytes=" + key + ",hex key=" + byteToHexString(key));
            logger.info("originalKey=" + originalKey + ",getBytes=" + key + ",hex key=" + byteToHexString(key));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    private static String Algorithm = "AES";
    private static String AlgorithmProvider = "AES/CBC/PKCS5Padding"; //算法/模式/补码方式

    public static IvParameterSpec getIv() throws UnsupportedEncodingException {
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes("utf-8"));

        System.out.println("偏移量：" + byteToHexString(ivParameterSpec.getIV()));
        logger.info(iv + "偏移量（byteToHex）：" + byteToHexString(ivParameterSpec.getIV()));

        return ivParameterSpec;
    }

    public static String encrypt(String src) throws NoSuchPaddingException, UnsupportedEncodingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException {
        return byteToHexString(encrypt(src, CryptoUtil.key));
    }

    /**
     * 加密使用全局的CryptoUtil.iv
     */
    public static byte[] encrypt(String src, byte[] key) throws NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException, InvalidAlgorithmParameterException, InvalidAlgorithmParameterException {
        SecretKey secretKey = new SecretKeySpec(key, Algorithm);
        IvParameterSpec ivParameterSpec = getIv();
        Cipher cipher = Cipher.getInstance(AlgorithmProvider);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
        byte[] cipherBytes = cipher.doFinal(src.getBytes(Charset.forName("utf-8")));
        return cipherBytes;
    }

    public static String decrypt(String src) throws NoSuchPaddingException, UnsupportedEncodingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException {
        return new String(decrypt(src, CryptoUtil.key), "UTF-8");
    }

    /**
     * 解密使用全局的CryptoUtil.iv
     */
    public static byte[] decrypt(String src, byte[] key) throws NoSuchPaddingException, NoSuchAlgorithmException, UnsupportedEncodingException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        SecretKey secretKey = new SecretKeySpec(key, Algorithm);

        IvParameterSpec ivParameterSpec = getIv();
        Cipher cipher = Cipher.getInstance(AlgorithmProvider);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
        byte[] hexBytes = hexStringToBytes(src);
        byte[] plainBytes = cipher.doFinal(hexBytes);
        return plainBytes;
    }

    /**
     * 将byte转换为16进制字符串
     *
     * @param src
     * @return
     */
    public static String byteToHexString(byte[] src) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xff;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                sb.append("0");
            }
            sb.append(hv);
        }
        return sb.toString();
    }

    /**
     * 将16进制字符串装换为byte数组
     *
     * @param hexString
     * @return
     */
    public static byte[] hexStringToBytes(String hexString) {
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] b = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            b[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return b;
    }

    private static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }


    /**
     * 解密AES加密过的字符串
     *
     * @param content  AES加密过过的内容
     * @param password 加密时的密码
     * @return 明文
     */
    public static byte[] decrypt(byte[] content, String password) {
        try {
            KeyGenerator _generator = KeyGenerator.getInstance("AES");
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
            secureRandom.setSeed(password.getBytes());
            _generator.init(128, secureRandom);
            SecretKey secretKey = _generator.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥
            SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥
            Cipher cipher = Cipher.getInstance("AES");// 创建密码器
            cipher.init(Cipher.DECRYPT_MODE, key);// 初始化为解密模式的密码器
            byte[] result = cipher.doFinal(content);
            return result; // 明文

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * AES加密字符串
     *
     * @param content  需要被加密的字符串
     * @param password 加密需要的密码
     * @return 密文
     */
    public static byte[] encrypt(String content, String password) {
        try {
            KeyGenerator _generator = KeyGenerator.getInstance("AES");
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
            secureRandom.setSeed(password.getBytes());
            _generator.init(128, secureRandom);
            SecretKey secretKey = _generator.generateKey();


            byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥，如果此密钥不支持编码，则返回null。

            SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥

            Cipher cipher = Cipher.getInstance("AES");// 创建密码器

            byte[] byteContent = content.getBytes("utf-8");

            cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化为加密模式的密码器

            byte[] result = cipher.doFinal(byteContent);// 加密

            return result;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String args[]) throws Exception {
        Base64.Decoder base64Decoder = Base64.getDecoder();
//        System.out.println(CryptoUtil.AES_CBC_Encrypt("888888"));
//        String aaa=CryptoUtil.AES_CBC_Encrypt("888888");
//        System.out.println(CryptoUtil.AES_CBC_Decrypt(aaa));

/*
        System.out.println("===========");
        System.out.println("=========iv==" + byteToHexString(iv.getBytes("UTF-8")));
*/

//        String encrypt=new String(CryptoUtil.encrypt("888888","amproduct"));
//        System.out.println(encrypt);
//        byte[] enbyte = CryptoUtil.encrypt("62a6d26b91ad898efeb4bb099ff2ef63", "amproduct");
//        System.out.println("enbyte length=" + enbyte.length);
//        System.out.println(new String(CryptoUtil.decrypt(enbyte, "amproduct"), "UTF8"));


       /* System.out.println(CryptoUtil.decrypt("2c2935512cbdab5dbfe9b67f54e77a64"));
        System.out.println(CryptoUtil.decrypt("2c2935512cbdab5dbfe9b67f54e77a64"));
        System.out.println(CryptoUtil.decrypt("2c2935512cbdab5dbfe9b67f54e77a64"));
        System.out.println(CryptoUtil.decrypt("2c2935512cbdab5dbfe9b67f54e77a64"));*/
//        System.out.println(CryptoUtil.decrypt("21218cca77804d2ba1922c33e0151105"));
//
//        System.out.println(CryptoUtil.decrypt("2c2935512cbdab5dbfe9b67f54e77a64"));
//        System.out.println(CryptoUtil.encrypt("Gl011511"));
//        System.out.println(CryptoUtil.decrypt("a6ad5692340d7cd0bbf2668b47f723b5"));
        System.out.println(CryptoUtil.decrypt("a6ad5692340d7cd0bbf2668b47f723b5"));



/*
        try {
            // byte key[] = generatorKey();
            // 密钥必须是16的倍数
            byte key[] = "1234567890ABCDEF1234567890ABCDEf".getBytes("utf-8");//hexStringToBytes("0123456789ABCDEF");
            String src = "werty7890";
            System.out.println("密钥:" + byteToHexString(key));
            System.out.println("原字符串:" + src);
            String enc = byteToHexString(encrypt(src, key));
            System.out.println("加密：" + enc);
            System.out.println("解密：" + new String(decrypt(enc, key), "utf-8"));
            enc = "904c2b2f59520b76c2a790da1d70efa8";
            System.out.println("加密---====：" + enc);
            System.out.println("解密：" + new String(decrypt(enc, key), "utf-8"));
            System.out.println("解密：" + new String(decrypt("89d6cdc0f945b4f9563dd63156aa05cb", key), "utf-8"));
            System.out.println("加密---===================");
            System.out.println("destr="+encrypt("fdsfdsfdsfdsfdsf"));
            String destr=encrypt("zzp@glsc-password-ff#$#@%$%$%#");
            System.out.println(destr);
            System.out.println("destr="+decrypt(destr));
            System.out.println("destr="+decrypt("2c2935512cbdab5dbfe9b67f54e77a64"));

        } catch (Exception e) {
            e.printStackTrace();

        }*/
    }

}
